home *** CD-ROM | disk | FTP | other *** search
- ;=============================================================================
- ; s_i2cbusIO.s: Assembler-Version der KICK-Pascal Prozedur i2cbusIO (seriell)
- ; Parameterübergabe (auf dem Stack):
- ; 12(A7).B: logische Busadresse -> D0
- ; 8(A7).L: Zeiger auf den I/O-Puffer -> A0
- ; 6(A7).W: Anzahl zu übertragender Daten -> D1
- ; 4(A7).W: Zeitschleifen-Durchgänge -> D5
- ; Rückgabewert:
- ; D0.W: Status, Bedeutung s. u.
- ;-----------------------------------------------------------------------------
- ; Funktionsweise:
- ; Startet den I²C-Bus und spricht den in D0 bezeichneten Chip an. Wenn D1
- ; negativ ist, werden -D1 Bytes vom Bus geholt und ab Adresse A0 im Speicher
- ; abgelegt, sonst +D1 Bytes ab A0 über den Bus abgeschickt. Die Busadresse
- ; (D0) wird dabei automatisch zur Schreib- bzw. Leseadresse gemäß I²C-Bus-
- ; Konvention korrigiert. Abschließend wird der I²C-Bus wieder gestoppt.
- ; Anmerkungen:
- ; 1. Die über D5 bestimmte Zeitschleife soll den Bustakt bremsen, wobei
- ; maximal 100 kHz zulässig sind, "zu langsam" gibt es dagegen am I²C-Bus
- ; NICHT. Auf normalen Amigas sollte D5=0 sein.
- ; 2. Mehr Bytes zum Lesen anzufordern, als der bereitgestellte Puffer fassen
- ; kann, ist ein Fehler, der nicht erkannt werden kann und wahrscheinlich
- ; mit einem GURU endet.
- ; 3. Bedeutung des Statusworts:
- ; 0 = fehlerfreie Übertragung
- ; 1 = unquittierte Daten
- ; 2 = angesprochener Chip antwortet nicht
- ; 3 = gesendete Daten wurden (ohne erkennbares Schema) zerstört
- ; 4 = gesendete Daten zu Null verfälscht
- ; 5 = gesendete Daten zu Einsen verfälscht
- ;=============================================================================
-
- ; interne Registerverwendung:
- ; D0: Datenbyte, das gesendet oder empfangen wird
- ; D1: Anzahl zu übertragende Bytes
- ; D2: Zähler über gesendete Bytes
- ; D3: Zähler über 8 Bits
- ; D4: Zähler für Zeitschleife
- ; D5: Grenze für Zeitschleife
- ; D6: Kontrollbyte beim Senden
- ; A0: Pufferzeiger
- ; A1: Adresse des CIA-Ports
-
- CIABPRA = $BFD000
- CIABDDRA = $BFD200
- ClkOutBit = 6 ; CIAB_COMRTS
- ClkInBit = 4 ; CIAB_COMCTS
- DataOutBit = 7 ; CIAB_COMDTR
- DataInBit = 5 ; CIAB_COMCD
-
- DELAY MACRO
- move.w d5,d4
- loop\@ dbf d4,loop\@
- ENDM
-
- ; Linker-Information:
- xdef s_i2cbusIO
-
- s_i2cbusIO:
- ; Parameter vom Stack holen:
- move.b 12(a7),d0
- move.l 8(a7),a0
- move.w 6(a7),d1
- move.w 4(a7),a1
-
- test:
- ; veränderte Register retten: D2,D3,D4,D5,D6
- movem.l d2-d6,-(a7)
-
- ; einen der Parameter noch ins richtige Register packen:
- move.w a1,d5
-
- ; CIA-Datenrichtungsregister initialisieren
- move.l #CIABDDRA,a1
- bset #ClkOutBit,(a1)
- bset #DataOutBit,(a1)
- bclr #ClkInBit,(a1)
- bclr #DataInBit,(a1)
-
- ; Bus in Ruhezustand bringen: DATA=HI, CLK=HI
- move.l #CIABPRA,a1
- bset #DataOutBit,(a1)
- bset #ClkOutBit,(a1)
-
- ; Bus starten (Protokollverletzung H->L): DATA=LO, CLK=LO
- DELAY
- bclr #DataOutBit,(a1)
- DELAY
- bclr #ClkOutBit,(a1)
- DELAY
-
- ; Soll ich senden oder empfangen?
- bclr #0,d0 ; Voreinstellung: Adresse als Sendeadresse
- tst.w d1
- bpl .zweck
- bset #0,d0 ; Adresse als Leseadresse
- .zweck:
-
- ; Daten senden, mindestens die Adresse, und evtl. <D1> weitere Bytes
- ; (Adressbyte steht bereits in D0):
- clr.w d2 ; Bytezähler auf Null
- SendLoop: ; das in D0 enthaltene Byte über den Bus schicken, MSB zuerst
- moveq.b #7,d3
- clr.b d6; Protokollbyte
- SBitLoop:
- btst d3,d0
- beq .SL1
- bset #DataOutBit,(a1) ; "1" senden
- bra .SL2
- .SL1 bclr #DataOutBit,(a1) ; "0" senden
- .SL2: ; Einen CLK-Impuls geben, um das Bit lesen zu lassen
- bset #ClkOutBit,(a1)
- DELAY
- btst #DataInBit,(a1)
- beq .SL3 ; SDA ist "0", nichts tun
- bset d3,d6 ; SDA ist "1", Bit im Protokollbyte setzen
- .SL3 bclr #ClkOutBit,(a1)
- DELAY
- dbf d3,SBitLoop
- cmp.b d6,d0
- bne SendErr ; Protokollbyte<>gesendetes Byte!
- ; 9. CLK-Impuls, um Quittungsbit zu lesen:
- bset #DataOutBit,(a1) ; sonst liest man nur das eigene LO!
- bset #ClkOutBit,(a1)
- DELAY
- btst #DataInBit,(a1)
- bne AckErr ; DATA=HI -> NAK, Übertragung abbrechen
- bclr #ClkOutBit,(a1)
- DELAY
- ; genug Daten gesendet?
- addq.w #1,d2 ; gesendetes Byte zählen
- cmp.w d1,d2 ; dran denken: Adressbyte wurde mitgezählt
- bgt SendEnd ; ja, fertig (schließt auch den Fall d1<0 ein)
- move.b (a0)+,d0 ; nein, Byte aus Puffer holen
- bra SendLoop
- AckErr:
- moveq.w #1,d0 ; Status = unquittiertes Byte
- tst.w d2 ; das wievielte Byte war es?
- bne BusStop ; irgendeins
- moveq.w #2,d0 ; sonst: Status = unquittiertes Adressbyte
- bra BusStop
- SendErr:
- bset #ClkOutBit,(a1) ; Noch eben das Quittungsbit anfordern, auch wenn
- DELAY ; das Bit selbst jetzt egal ist.
- bclr #ClkOutBit,(a1) ; Sonst könnte aber die Stoppbedingung am Bus
- DELAY ; verloren gehen!
- moveq.w #5,d0 ; Status = Daten zu 1 verfälscht
- cmp.b #255,d6 ; stimmt das überhaupt?
- beq BusStop ; ja
- moveq.w #4,d0 ; Status = Daten zu 0 verfälscht
- cmp.b #0,d6 ; stimmt?
- beq BusStop ; ja
- moveq.w #3,d0 ; Status = Daten irgendwie zerstört
- bra BusStop
- SendEnd:
- tst.w d1
- bmi RecvLoop ; es sollen auch noch Bytes empfangen werden
- moveq.w #0,d0 ; Status = OK
- bra BusStop
-
- ; soviele Bytes empfangen, wie in A1 angegeben:
- RecvLoop: ; ein Byte vom Bus holen, MSB zuerst, und in D0 zusammensetzen
- bset #DataOutBit,(a1) ; DATA-Leitung freigeben
- clr.b d0
- moveq.b #7,d3
- RBitLoop:
- ; Einen CLK-Impuls geben, ein Bit lesen:
- bset #ClkOutBit,(a1)
- DELAY
- btst #DataInBit,(a1)
- beq .RL1 ; "0" empfangen, nichts tun
- bset d3,d0 ; "1" empfangen, entsprechendes Bit setzen
- .RL1 bclr #ClkOutBit,(a1)
- DELAY
- dbf d3,RBitLoop
- move.b d0,(a0)+ ; Byte im Puffer speichern
- ; Quittierungsbit senden, "0", außer nach dem letzten Byte:
- addq.w #1,d1 ; empfangenes Byte zählen
- beq .RL2 ; letztes Byte, DATA auf HI lassen
- bclr #DataOutBit,(a1) ; nein, DATA=LO
- .RL2: ; CLK-Impuls geben, Quittungsbit lesen lassen:
- bset #ClkOutBit,(a1)
- DELAY
- bclr #ClkOutBit,(a1)
- DELAY
- ; alle Daten empfangen?
- tst.w d1
- bne RecvLoop ; nein, weitermachen
- moveq.w #0,d0 ; Status: OK
-
- BusStop: ; I²C-Bus stoppen (Protokollverletzung L->H): CLK=HI, DATA=HI
- ; zunächst noch CLK=LO, DATA=LO sicherstellen:
- bclr #ClkOutBit,(a1)
- bclr #DataOutBit,(a1)
-
- DELAY
- bset #ClkOutBit,(a1)
- DELAY
- bset #DataOutBit,(a1)
- DELAY
-
- ; gerettete Register zurückholen: D2,D3,D4,D5,D6
- movem.l (a7)+,d2-d6
- rts
-
- end
-
-